Skip to content

feat: provided-style extensions and manifest-libs#791

Open
jbachorik wants to merge 48 commits intodevelopfrom
jb/configurations
Open

feat: provided-style extensions and manifest-libs#791
jbachorik wants to merge 48 commits intodevelopfrom
jb/configurations

Conversation

@jbachorik
Copy link
Copy Markdown
Collaborator

@jbachorik jbachorik commented Jan 13, 2026

Rationale

BTrace has historically relied on libs=<profile> and $BTRACE_HOME/btrace-libs/<profile>/{boot,system}/*.jar to make application APIs (Spark, Hadoop, Kafka, …) visible to probes. That model has three structural problems:

  • Classpath pollution. Profile JARs are appended to the bootstrap and system class loaders, which is highly privileged, conflicts with application shading, and cannot be isolated per probe.
  • Fragile packaging. Resolution is heuristic (hardcoded agent-JAR name, URL string slicing, per-OS quirks). Renaming, JPMS, or non-filesystem deployments break it.
  • Doesn't ship. Spark drivers/executors, Hadoop containers, and Kubernetes pods don't have a shared $BTRACE_HOME with a matching profile layout. Users end up with custom init containers, sidecars, or wrapper scripts just to deliver one extra JAR.

This PR introduces three complementary mechanisms to fix this: provided-style extensions (APIs on bootstrap, implementation reflective and isolated), @ExternalType adapter generation (build-time boilerplate elimination), and fat agents (a single JAR containing the agent plus embedded extensions, built via a Gradle or Maven plugin).

Usability Improvements

  • Single-JAR deployment. java -javaagent:btrace-agent-fat.jar is now enough for Spark/Hadoop/K8s — no $BTRACE_HOME, no profile directory, no sidecars.
  • No more classpath injection. Provided-style extensions keep only minimal API types on bootstrap; the impl lives in an isolated extension class loader and resolves app types via TCCL. Application shading and version conflicts stop being BTrace's problem.
  • @ExternalType annotation processor. Annotate an interface with @ExternalType("fully.qualified.AppType") and the build generates a companion $Ext class with typed, lazily-resolved static dispatchers per method. No manual MethodHandleCache / ClassLoadingUtil boilerplate for the common case.
  • Build-time tooling. New Gradle plugins (org.openjdk.btrace.extension, org.openjdk.btrace.fat-agent) and a btrace-maven-plugin handle API/impl split, manifest metadata, permission scanning, relocations, multi-project auto-discovery, and annotation processor registration.
  • Single-source module layout. Extensions now use a single Gradle module with separate source sets (api, impl, main) rather than separate projects, which simplifies build setup.
  • Declarative, manifest-driven libs. The legacy libs= heuristic is replaced by explicit manifest attributes (BTrace-Boot-Libs, BTrace-System-Libs, BTrace-Embedded-Extensions) with deduplication, validation, and diagnostics.
  • Working examples. btrace-extensions/examples/btrace-spark and btrace-extensions/examples/btrace-hadoop demonstrate the pattern end-to-end, including @ExternalType-based adapters.

Quick Start

1. Build a fat agent with Gradle

plugins {
    id 'org.openjdk.btrace.fat-agent' version "${btraceVersion}"
}

btraceFatAgent {
    baseName = 'my-btrace-agent'
    embedExtensions {
        project(':my-spark-extension')              // multi-project
        maven('io.btrace:btrace-metrics:2.3.0')     // external
    }
}
./gradlew fatAgentJar
# -> build/libs/my-btrace-agent.jar

2. Attach it

java -javaagent:/path/to/my-btrace-agent.jar=debug=true,port=2020 -jar your-app.jar

Embedded extensions are discovered automatically from the JAR manifest — no $BTRACE_HOME required.

3. Write a provided-style extension with @ExternalType

Declare the external type contract in the API source set — the annotation processor (auto-registered by the Gradle plugin) generates SparkListenerJobStartType$Ext:

// src/api/java/com/example/spark/api/SparkListenerJobStartType.java
@ExternalType("org.apache.spark.scheduler.SparkListenerJobStart")
public interface SparkListenerJobStartType {
    int jobId();
    long time();
}

Use the generated class directly in the impl — no manual MethodHandle or ClassLoadingUtil code needed:

// src/impl/java/com/example/spark/impl/SparkApiImpl.java
public final class SparkApiImpl extends Extension implements SparkApi {
    @Override
    public void onJobStart(Object event) {
        int  jobId = SparkListenerJobStartType$Ext.jobId(event);
        long ts    = SparkListenerJobStartType$Ext.time(event);
        // emit metrics / logs...
    }
}

The generated dispatcher resolves the external class lazily on the first call (via the object's defining class loader), caches the MethodHandle, and retries on subsequent calls if the class wasn't loaded yet — no ExceptionInInitializerError at extension load time.

For cases @ExternalType doesn't cover (field access, constructors, non-public visibility), the manual ClassLoadingUtil / MethodHandleCache helpers still work alongside generated adapters.

4. (Optional) Static external methods

Annotate an interface method with @ExternalType.Static — the processor generates a findStatic + TCCL-based dispatcher:

@ExternalType("org.example.Foo")
public interface FooType {
    @ExternalType.Static
    String create();  // -> Foo.create() via findStatic
}

Maven equivalent

<plugin>
  <groupId>org.openjdk.btrace</groupId>
  <artifactId>btrace-maven-plugin</artifactId>
  <configuration>
    <extensions>
      <extension>io.btrace:btrace-metrics:${btrace.version}</extension>
    </extensions>
  </configuration>
</plugin>

See docs/architecture/provided-style-extensions.md and docs/architecture/migrating-from-libs-profiles.md for the full walk-through.

Drawbacks and Remaining Issues

  • @ExternalType v1 scope limits. The annotation processor does not cover field access (read/write), constructors, instanceof/checkcast on external types, chained @ExternalType references, or non-public methods. Use ClassLoadingUtil / MethodHandleCache directly for these.
  • No hot-reload for embedded extensions. Updating an extension in a fat agent requires rebuilding the JAR and restarting the target JVM.
  • Larger artifact. A fat agent is strictly bigger than the minimal agent; users who ship BTrace through a managed $BTRACE_HOME don't benefit from embedding.
  • More boilerplate than profiles for non-@ExternalType cases. When @ExternalType doesn't cover your case, the provided-style pattern still requires explicit API/impl split and reflective adapters. It's a deliberate trade-off (isolation + portability), but the migration cost from existing profile-based setups is real.
  • Reflective cost at the hot path. Even with cached MethodHandles (generated or manual), an adapter call is more expensive than a direct invocation. Very high-frequency probes should be profiled.
  • libs= / profiles= still accepted. They are deprecated and log a warning; planned removal is N+2 minor releases. Until then, both code paths coexist and users can mix them (not recommended).
  • Escape hatch kept for now. -Dbtrace.system.appendJar=/abs/path/lib.jar (requires -Dbtrace.trusted=true) exists for cases where immediate migration is impossible. It's restricted to BTRACE_HOME by default and is explicitly discouraged — expect it to be removed together with libs=.
  • Fat-agent plugin API surface. The Gradle/Maven plugins are new; DSL and task names may still shift before the first stable release cut.

Documentation

Document Description
Provided-Style Extensions API on bootstrap, impl via TCCL, @ExternalType processor
Fat Agent Plugin Architecture Single-JAR deployment design
Migrating from libs/profiles Step-by-step migration guide
Extension Development Guide Building extensions from scratch
Extension Interface Rules Rules for @ExternalType and API interfaces
Gradle Plugin README Extension + fat-agent plugins

Breaking Changes

  • libs= and profiles= are deprecated. Planned removal: N+2 minor releases. A runtime warning is emitted on use.

🤖 Generated with Claude Code


This change is Reviewable

@jbachorik jbachorik added the AI AI-generated code label Jan 13, 2026
Copy link
Copy Markdown

@reviewabot reviewabot Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the pull request diff is too large to be displayed directly on GitHub. Here are some general recommendations for handling large pull requests:

  1. Break Down the PR: Try to break down the pull request into smaller, more manageable chunks. This makes it easier to review and ensures that each part can be thoroughly checked.

  2. Review Locally: Clone the repository and check out the branch locally. This allows you to review the changes using your preferred tools and environment.

  3. Focus on Key Areas: Identify and focus on the key areas of the code that are most critical or have the highest impact. This can help prioritize the review process.

  4. Automated Tools: Use automated code review tools and linters to catch common issues and enforce coding standards.

  5. Collaborate with the Team: If possible, involve multiple reviewers to share the workload and get different perspectives on the changes.

If you can provide a smaller subset of the changes or specific files that need review, I'd be happy to help with a more detailed review.

@jbachorik jbachorik changed the title fix(agent,client,tests): probe listing after disconnect and test isolation feat: manifest-libs, provided-style extensions, permission removal, and fixes Jan 13, 2026
@jbachorik jbachorik changed the title feat: manifest-libs, provided-style extensions, permission removal, and fixes feat: provided-style extensions and manifest-libs Jan 13, 2026
@jbachorik jbachorik requested a review from Copilot January 13, 2026 16:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces provided-style extensions and manifest-driven library loading to enable tracing application-specific classes without polluting the application classpath. The core innovation is using reflection and object hand-off patterns to access application classes at runtime, keeping BTrace isolated.

Changes:

  • New extension utilities (ClassLoadingUtil, MethodHandleCache) for runtime class resolution and reflective method access
  • Manifest-driven library path resolution (AgentManifestLibs) with security restrictions to BTRACE_HOME
  • Refactored agent classpath processing with deduplication and better error handling
  • Example extensions for Spark and Hadoop demonstrating the provided-style pattern
  • Comprehensive architecture documentation and migration guides
  • Deprecation of libs/profiles mechanism with escape hatch for edge cases

Reviewed changes

Copilot reviewed 25 out of 26 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
settings.gradle Added example extension modules (btrace-spark, btrace-hadoop)
integration-tests/src/test/java/tests/RuntimeTest.java Fixed debug flag insertion and added timing delays for test stability
integration-tests/src/test/java/tests/ManifestLibsTests.java New test suite for manifest-libs feature
integration-tests/src/test/java/tests/BTraceFunctionalTests.java Improved unattended test with better synchronization and cleanup
integration-tests/build.gradle Added test property for skipping preconfigured libs
docs/examples/README.md Guide for building and configuring provided-style extension examples
docs/architecture/provided-style-extensions.md Comprehensive guide on provided-style extension pattern
docs/architecture/migrating-from-libs-profiles.md Migration guide from deprecated libs/profiles to extensions
docs/architecture/agent-manifest-libs.md Design document for manifest-driven library loading
compile.log Build artifact that should not be committed
btrace-extensions/examples/btrace-spark/* Example Spark extension with API and provided-style implementation
btrace-extensions/examples/btrace-hadoop/* Example Hadoop extension with API and provided-style implementation
btrace-extension/src/main/java/org/openjdk/btrace/extension/util/MethodHandleCache.java Cache for reflective method handles to reduce lookup overhead
btrace-extension/src/main/java/org/openjdk/btrace/extension/util/ClassLoadingUtil.java Helper utilities for TCCL-based class loading and service discovery
btrace-client/src/main/java/org/openjdk/btrace/client/Main.java Removed exit hooks for list-only operations to prevent unintended probe removal
btrace-client/src/main/java/org/openjdk/btrace/client/Client.java Added agent-already-running detection and system property pass-through
btrace-agent/src/main/java/org/openjdk/btrace/agent/RemoteClient.java Improved disconnect handling with disconnecting flag
btrace-agent/src/main/java/org/openjdk/btrace/agent/Main.java Refactored classpath processing with manifest support, deduplication, and escape hatch for single-jar injection
btrace-agent/src/main/java/org/openjdk/btrace/agent/AgentManifestLibs.java New utility for manifest-driven library resolution with security checks
README.md Added deprecation notice for libs/profiles with migration guidance

Comment thread btrace-agent/src/main/java/org/openjdk/btrace/agent/AgentManifestLibs.java Outdated
Comment thread btrace-agent/src/main/java/org/openjdk/btrace/agent/AgentManifestLibs.java Outdated
Comment thread btrace-agent/src/main/java/org/openjdk/btrace/agent/Main.java Outdated
Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 13, 2026

@jbachorik I've opened a new pull request, #792, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 13, 2026

@jbachorik I've opened a new pull request, #793, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 13, 2026

@jbachorik I've opened a new pull request, #794, to work on those changes. Once the pull request is ready, I'll request review from you.

@jbachorik jbachorik closed this Mar 15, 2026
@jbachorik jbachorik reopened this Apr 6, 2026
@jbachorik
Copy link
Copy Markdown
Collaborator Author

ReDoS in EmbeddedExtensionRepository.isValidClassName — fixed in dbd3964

Addresses the CodeQL ReDoS alert (js/redos, alert #15) on the class-name validation pattern.

The regex had three ambiguities the engine could explore:

  1. Inner char class [a-zA-Z0-9_$]* inside the .-group and the $-group both allowed $
  2. The outer (\$[a-zA-Z_][a-zA-Z0-9_$]*)* group also started with $
  3. All three repetitions were standard (backtracking) *

On an input like A$A$A$A…! (trailing mismatch) this produced exponential partition searching before failing.

Fix: switch the three repetitions to possessive quantifiers (*+). Each commit is final, so the engine cannot re-partition $-separated tail segments. Match semantics are preserved for every accepted and rejected input in SecurityValidationTest > Class name validation (valid / invalid / special-chars / code-injection / null-and-empty — all green).

Stress-check: A$A × 30 + ! now rejects in ~0 ms instead of hanging.

Items 1–5 of the earlier review (unused Enumeration import, redundant homeStr null check, three zip-slip sites in FatAgentMojo) were already addressed in prior commits on this branch.

@jbachorik jbachorik marked this pull request as ready for review April 12, 2026 18:08
@jbachorik jbachorik requested a review from Copilot April 12, 2026 18:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 54 out of 55 changed files in this pull request and generated 12 comments.

Comment thread integration-tests/src/test/java/tests/RuntimeTest.java Outdated
Comment thread integration-tests/src/test/java/tests/RuntimeTest.java Outdated
Comment thread docs/Troubleshooting.md Outdated
Comment thread docs/BTraceTutorial.md Outdated
Comment thread docs/README.md
Comment thread btrace-agent/src/main/java/org/openjdk/btrace/agent/Main.java Outdated
Comment thread btrace-agent/src/test/java/org/openjdk/btrace/agent/AgentManifestLibsTest.java Outdated
Comment thread btrace-maven-plugin/build.gradle
Comment thread integration-tests/src/test/java/tests/RuntimeTest.java
jbachorik and others added 5 commits April 17, 2026 23:49
…ibs deprecation; provided-style helpers; examples; tests\n\n- agent: manifest-driven libs (flagged), centralized classpath append with dedup + diagnostics; deprecate libs (debug log); add single-jar system CL escape hatch; test knob scoped to manifest-libs\n- client: pass-through of btrace.* props to agent using $ system props\n- extension: add ClassLoadingUtil and MethodHandleCache for provided-style extensions\n- examples: add btrace-extensions/examples/{btrace-spark,btrace-hadoop} with README\n- docs: research + provided-style guide + migration + examples index; README deprecation note\n- tests: add ManifestLibsTests; gradle knob for btrace.test.skipLibs\n\nBREAKING CHANGE: libs/profiles deprecated with planned removal after N+2; prefer extensions
- Proactively retransform java.lang.Thread after startup scripts load
- Move initExtensions() after transformer is installed
- Add delay in RuntimeTest to allow traced app output after ready marker

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ation

- Add disconnecting flag to RemoteClient for immediate probe visibility
- Skip loadAgent when agent already running (check btrace.port)
- Add try-finally cleanup in tests to prevent port conflicts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…il/ClassLoadingUtil.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
jbachorik and others added 9 commits May 1, 2026 22:30
…cation

Add RunnableResult + compileAndLoad() to CompileTestHarness so compiled
classes can be loaded and invoked; add generatedAdapterInvokesRealMethod
test that exercises the full findVirtual + MethodHandle.invoke pipeline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… api source set

Wire btrace-extension-processor as an automatic apiAnnotationProcessor dependency
in BTraceExtensionPlugin so extension authors get adapter generation for free.
In-tree builds use the sibling project reference; external consumers resolve the
published Maven artifact by version.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…atestSupported

Apply Types#erasure() to return and parameter types in buildSpec() so that
parameterized types like List<String> produce raw-type literals (List.class)
in generated adapter source instead of the invalid List<String>.class form.
Replace @SupportedSourceVersion(RELEASE_8) with getSupportedSourceVersion()
returning SourceVersion.latestSupported() to eliminate the javac warning on
JDK 11+. Adds a test covering both parameterized-type cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…xternalType

- Add btrace-ext-test module: lightweight extension with ExternalDataType
  (@ExternalType interface) and ExternalTypeTestService to exercise the
  full annotation-processor → adapter → BTrace probe pipeline
- Add integration test (ExternalTypeAdapterIntegrationTest) verifying that
  a BTrace probe annotated with @injected can call an extension service
  backed by a generated $Ext adapter against a class present only in the
  target app's classloader
- Guard TCCL null in generated static-dispatch adapter (fallback to
  ClassLoader.getSystemClassLoader()) so adapters work on bootstrap threads
- Move buildSpec() call inside the try/catch in ExternalTypeProcessor so
  processor-internal errors are reported as compile errors, not crashes
- Add TCCL unit tests: staticDispatcherResolvesViaContextClassLoader and
  staticDispatcherFallsBackToSystemLoaderWhenTcclNull
- Simplify AdapterEmitter: single-pass paramAndArgLists() replaces two
  separate passes; extract shared formatErrors() helper in CompileTestHarness;
  pass externalFqn into buildSpec() to avoid re-fetching the annotation
- Add explanatory comment to empty catch in SparkApiImpl example

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 85 out of 109 changed files in this pull request and generated 6 comments.

Comment thread docs/GettingStarted.md Outdated
Comment thread integration-tests/src/test/java/tests/RuntimeTest.java
Comment thread integration-tests/src/test/java/tests/RuntimeTest.java
@jbachorik
Copy link
Copy Markdown
Collaborator Author

@copilot apply changes based on the comments in this thread

…arations, broken link

Agent-Logs-Url: https://github.com/btraceio/btrace/sessions/697859ef-3024-46cc-915b-7638aaafca8d

Co-authored-by: jbachorik <738413+jbachorik@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented May 1, 2026

@copilot apply changes based on the comments in this thread

Applied all changes from the review thread in commit 638722f:

  1. docs/GettingStarted.md:685 – Fixed the broken link: troubleshooting.mdTroubleshooting.md
  2. BTraceFatAgentPluginTest.java:13-14 – Removed unused JarFile and Manifest imports
  3. SecurityValidationTest.java – Formatting fixed via spotlessApply (Google Java Format)
  4. MethodHandleCache.java:22-39 – Removed throws NoSuchMethodException, IllegalAccessException from findVirtual and findStatic since exceptions are always caught and wrapped as LookupRuntimeException
  5. RuntimeTest.java:1002 and :1138 – Replaced the brittle argVals.add(4, "-v") with dynamic computation: argVals.add(argVals.indexOf("org.openjdk.btrace.boot.Loader") + 1, "-v")

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 85 out of 109 changed files in this pull request and generated 8 comments.

Comment thread docs/Troubleshooting.md
Comment on lines +5 to +6
> **Note:** Examples use `btrace.jar` -- the single masked JAR (BTrace 2.2+). If using a legacy multi-JAR distribution, replace `btrace.jar` with `btrace-agent.jar` (and add `-Xbootclasspath/a:btrace-boot.jar` where needed).

Comment thread docs/FAQ.md
Comment on lines 146 to 151

Or via agent:
```bash
java -javaagent:btrace-agent.jar=script=MyTrace.class,filterValue=custom MyApp
java -javaagent:btrace.jar=script=MyTrace.class,filterValue=custom MyApp
```

Comment thread docs/GettingStarted.md
Comment on lines +24 to +36
class BTraceFatAgentPluginTest {

@TempDir
Path projectDir;

private File buildFile;
private File settingsFile;

@BeforeEach
void setUp() throws IOException {
buildFile = projectDir.resolve("build.gradle").toFile();
settingsFile = projectDir.resolve("settings.gradle").toFile();

Comment thread btrace-client/src/main/java/org/openjdk/btrace/client/Client.java
Comment thread docs/README.md
Comment thread docs/QuickReference.md
@jbachorik
Copy link
Copy Markdown
Collaborator Author

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented May 1, 2026

@copilot apply changes based on the comments in this thread

Applied all changes from the review thread in commit 3d2b213:

  1. Doc link casing (GettingStarted.md, FAQ.md, Troubleshooting.md, README.md, QuickReference.md) – Fixed all broken relative links with incorrect casing: gettingStarted.mdGettingStarted.md, troubleshooting.mdTroubleshooting.md, faq.mdFAQ.md, btraceTutorial.mdBTraceTutorial.md, quickReference.mdQuickReference.md, onelinerGuide.mdOnelinerGuide.md, Readme.mdREADME.md
  2. Client.java:677-680 – Fixed VirtualMachine vm resource leak: moved declaration outside the try block and added a finally block calling vm.detach(), so the connection is always released including the early-return path when the agent is already running
  3. BTraceFatAgentPluginTest.java – Reformatted via spotlessApply (Google Java Format 2-space indents)

…ations

- NestedJarExtensionClassLoader: track bootstrap JarFile as a field and
  close it in close() to prevent fd leak; replace manual buffer copy loop
  with Files.copy
- MethodHandleCache: use putIfAbsent return value to avoid a third map
  lookup on concurrent-miss path
- AgentManifestLibs: call locateAgentPath once (was called twice per
  resolve); hoist home.toRealPath() out of the per-entry loop; remove
  redundant 'Package-private for testing' comments; change readManifest
  to accept Path directly
- BTraceFatAgentPlugin: delete dead resolveExtensions wrapper method
- PermissionScanner: delete dead scanClass method and its two unused imports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 87 out of 111 changed files in this pull request and generated 1 comment.

Comment thread btrace-instr/build.gradle
Comment on lines +54 to 57
// Include exported extension APIs explicitly without depending on internal source-set names.
def utilsApi = files(project(':btrace-extensions:btrace-utils').tasks.named('buildApiJar'))
def statsdApi = files(project(':btrace-extensions:btrace-statsd').tasks.named('buildApiJar'))
def fullCp = rtCp.plus(extraCp).plus(utilsApi).plus(statsdApi)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI AI-generated code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants